{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 遗传算法的种群模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "importing Jupyter notebook from DNA.ipynb\n",
      "importing Jupyter notebook from ScoreAnalyzer.ipynb\n"
     ]
    }
   ],
   "source": [
    "import configure\n",
    "import DNA\n",
    "import random\n",
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#种群类，存储每代的种群个体\n",
    "class Population:\n",
    "\n",
    "    def __init__(self, size, length, rate=0.01, modifiers=[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]):\n",
    "        if size < 2:\n",
    "            print(\"Size of population must be greater than 1\")\n",
    "            return\n",
    "        if length < 1:\n",
    "            print(\"Length of DNA must be greater than 0\")\n",
    "            return\n",
    "\n",
    "        self.size = size\n",
    "        self.length = length\n",
    "        self.rate = rate\n",
    "        self.populace = []\n",
    "        self.__totalFitness = 0\n",
    "\n",
    "        for i in range(0, size):\n",
    "            newDNA = DNA.DNA(length)\n",
    "            self.__totalFitness += newDNA.getFitness(modifiers)\n",
    "            self.populace.append(newDNA)\n",
    "\n",
    "    #进化函数，产生下一代种群\n",
    "    def getGeneration(self, modifiers, deterministic=False):\n",
    "        if deterministic:\n",
    "            return self.__getDeterministic(modifiers)\n",
    "        else:\n",
    "            return self.__getProbabilistic(modifiers)\n",
    "\n",
    "    #选择确定性方式产生下一代种群，私有方法\n",
    "    def __getDeterministic(self, modifiers):\n",
    "        self.populace = sorted(self.populace, key=lambda dna: dna.getFitness(modifiers), reverse=True)\n",
    "        newPopulace = []\n",
    "        fittestChild = None\n",
    "        newTotalFitness = 0\n",
    "        i = 0\n",
    "        while len(newPopulace) < self.size:\n",
    "            # Breed this person with up to sqrt(size) lesser beings\n",
    "            for j in range(0, int(math.sqrt(self.size - len(newPopulace)))):\n",
    "                if len(newPopulace) >= self.size: break\n",
    "                parent1 = self.populace[i]\n",
    "                parent2 = self.populace[i + j]\n",
    "                child = parent1.breed(parent2)\n",
    "                child.mutate(self.rate)\n",
    "\n",
    "                newTotalFitness += child.getFitness(modifiers)\n",
    "                newPopulace.append(child)\n",
    "\n",
    "                if fittestChild is None:\n",
    "                    fittestChild = child\n",
    "                elif child.getFitness(modifiers) > fittestChild.getFitness(modifiers):\n",
    "                    fittestChild = child\n",
    "            i += 1\n",
    "\n",
    "        self.populace = newPopulace\n",
    "        self.__totalFitness = newTotalFitness\n",
    "        fitnessArray = fittestChild.getFitnessArray()\n",
    "        print(\"---------------------------------------------\")\n",
    "        print(\"Cumulative: \" + str(fittestChild.getFitness(modifiers)))\n",
    "        print(\"    Motion:       \" + str(fitnessArray[0]))\n",
    "        print(\"    Consonance:   \" + str(fitnessArray[1]))\n",
    "        print(\"    Consistency:  \" + str(fitnessArray[2]))\n",
    "        print(\"    Macroharmony: \" + str(fitnessArray[3]))\n",
    "        print(\"    Centricity:   \" + str(fitnessArray[4]))\n",
    "        print(\"    Cohesion:     \" + str(fitnessArray[5]))\n",
    "        print(\"    Note Length:  \" + str(fitnessArray[6]))\n",
    "        print(\"    Octave:       \" + str(fitnessArray[7]))\n",
    "        print(\"    Common Notes: \" + str(fitnessArray[8]))\n",
    "\n",
    "        return fittestChild\n",
    "\n",
    "    #选择概率性方式产生下一代种群，私有方法\n",
    "    def __getProbabilistic(self, modifiers):\n",
    "        probabilities = []\n",
    "        # Produce relative probabilities\n",
    "        for dna in self.populace:\n",
    "            probabilities.append(dna.getFitness(modifiers) / self.__totalFitness)\n",
    "\n",
    "        # Produce a new population via that whole spooky birds and bees stuff\n",
    "        newPopulace = []\n",
    "        newTotalFitness = 0\n",
    "        fittestChild = None\n",
    "        while len(newPopulace) < self.size:\n",
    "            rand = random.random()\n",
    "            cumulativeProbability = 0\n",
    "            parent1 = None\n",
    "            for index, value in enumerate(self.populace):\n",
    "                cumulativeProbability += probabilities[index]\n",
    "                if cumulativeProbability >= rand:\n",
    "                    parent1 = self.populace[index]\n",
    "                    break\n",
    "\n",
    "            rand = random.random()\n",
    "            cumulativeProbability = 0\n",
    "            parent2 = None\n",
    "            for index, value in enumerate(self.populace):\n",
    "                cumulativeProbability += probabilities[index]\n",
    "                if cumulativeProbability >= rand:\n",
    "                    parent2 = self.populace[index]\n",
    "                    break\n",
    "\n",
    "            child = parent1.breed(parent2)\n",
    "            rand = random.random()\n",
    "            child.mutate(self.rate)\n",
    "            newTotalFitness += child.getFitness(modifiers)\n",
    "            newPopulace.append(child)\n",
    "            if fittestChild is None:\n",
    "                fittestChild = child\n",
    "            elif child.getFitness(modifiers) > fittestChild.getFitness(modifiers):\n",
    "                fittestChild = child\n",
    "\n",
    "        self.populace = newPopulace\n",
    "        self.__totalFitness = newTotalFitness\n",
    "        fitnessArray = fittestChild.getFitnessArray()\n",
    "        print(\"---------------------------------------------\")\n",
    "        print(\"Cumulative: \" + str(fittestChild.getFitness(modifiers)))\n",
    "        print(\"    Motion:       \" + str(fitnessArray[0]))\n",
    "        print(\"    Consonance:   \" + str(fitnessArray[1]))\n",
    "        print(\"    Consistency:  \" + str(fitnessArray[2]))\n",
    "        print(\"    Macroharmony: \" + str(fitnessArray[3]))\n",
    "        print(\"    Centricity:   \" + str(fitnessArray[4]))\n",
    "        print(\"    Cohesion:     \" + str(fitnessArray[5]))\n",
    "        print(\"    Note Length:  \" + str(fitnessArray[6]))\n",
    "        print(\"    Octave:       \" + str(fitnessArray[7]))\n",
    "        print(\"    Common Notes: \" + str(fitnessArray[8]))\n",
    "\n",
    "        return fittestChild\n",
    "\n",
    "    #返回当代种群\n",
    "    def getPopulace(self):\n",
    "        return self.populace"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:Empty]",
   "language": "python",
   "name": "conda-env-Empty-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
